package com.kubepartners.impactmodel.translator;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import com.kubepartners.impactmodel.translator.graphml.GraphmlDomWriter;
import com.kubepartners.impactmodel.translator.graphml.GraphmlMeasurementReader;
import com.kubepartners.impactmodel.translator.graphml.GraphmlReader;
import com.kubepartners.impactmodel.translator.graphml.GraphmlResultsReader;
import com.kubepartners.impactmodel.model.Graph;

public class GraphManager {
	
	public static Graph read(String filename) {
		GraphReader gr = null;
		// Create a JAXP SAXParserFactory and configure it
		if (filename.endsWith(".graphml") || filename.endsWith(".xml")) {
			gr = new GraphmlReader();
		} else {
			throw new RuntimeException("File format not supported!");
		}
		
        parse(filename, gr);
		
        // return Graph
        return gr.readGraph(null);
	}
	
	public static Graph read(InputStream is) {
		GraphReader gr =  new GraphmlReader();
        parse(is, gr);
		
        // return Graph
        return gr.readGraph(null);
	}
	
	public static Graph readResults(Graph graph, String filename) {
		GraphReader gr = null;
		// Create a JAXP SAXParserFactory and configure it
		if (filename.endsWith(".graphml") || filename.endsWith(".xml")) {
			gr = new GraphmlResultsReader();
			gr.setGraph(graph);
		} else {
			throw new RuntimeException("File format not supported!");
		}
		
        parse(filename, gr);
		
        // return Graph
        return gr.readGraph(null);
	}

	public static Graph update(Graph graph, String filename) {
		GraphReader gr = null;
		// Create a JAXP SAXParserFactory and configure it
		if (filename.endsWith(".graphml") || filename.endsWith(".xml")) {
			gr = new GraphmlMeasurementReader();
			gr.setGraph(graph);
		} else {
			throw new RuntimeException("File format not supported!");
		}
		
        parse(filename, gr);
		
        // return Graph
        return gr.readGraph(null);
	}
	
	/**
     * Convert from a filename to a file URL.
     */
    private static String convertToFileURL(String filename) {
        try {
			return new File(filename).toURL().toString();
		} catch (MalformedURLException e) {
			throw new RuntimeException("Invalid file URL!", e);
		}
    }
    
    public static void write(Graph g, String filename) {
    	GraphWriter gw = null;
		if (filename.endsWith(".graphml")  || filename.endsWith(".xml")) {
			gw = new GraphmlDomWriter();
			File f = new File(filename);
			FileOutputStream fos = null;
			try {
				fos = new FileOutputStream(f);
			} catch (FileNotFoundException e) {
				throw new RuntimeException("Cannot write to File", e);
			}
			gw.write(g, fos);
		} else {
			throw new RuntimeException("Unknown filetype '" + filename + "'");
		}
    }
    
    private static void parse(String filename, GraphReader gr) {
		SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setNamespaceAware(true);

		// Create a JAXP SAXParser
        SAXParser saxParser;
		try {
			saxParser = spf.newSAXParser();
			 // Get the encapsulated SAX XMLReader
	        XMLReader xmlReader = saxParser.getXMLReader();
	        // Set the ContentHandler of the XMLReader
	        xmlReader.setContentHandler((ContentHandler) gr);
	        // Set an ErrorHandler before parsing
	        xmlReader.setErrorHandler(new DefaultErrorHandler());
	        // Tell the XMLReader to parse the XML document
	        xmlReader.parse(convertToFileURL(filename));       
		} catch (ParserConfigurationException e) {
			throw new RuntimeException(e);
		} catch (SAXException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
    
    private static void parse(InputStream is, GraphReader gr) {
		SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setNamespaceAware(true);

		// Create a JAXP SAXParser
        SAXParser saxParser;
		try {
			saxParser = spf.newSAXParser();
			 // Get the encapsulated SAX XMLReader
	        XMLReader xmlReader = saxParser.getXMLReader();
	        // Set the ContentHandler of the XMLReader
	        xmlReader.setContentHandler((ContentHandler) gr);
	        // Set an ErrorHandler before parsing
	        xmlReader.setErrorHandler(new DefaultErrorHandler());
	        // Tell the XMLReader to parse the XML document
	        xmlReader.parse(new InputSource(is));       
		} catch (ParserConfigurationException e) {
			throw new RuntimeException(e);
		} catch (SAXException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

}
